package com.ncu.xrpc.zk;

import com.ncu.xrpc.ServiceDiscovery;
import com.ncu.xrpc.constant.Contant;
import lombok.extern.slf4j.Slf4j;
import org.I0Itec.zkclient.ZkClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by IntelliJ IDEA.
 * User: xiongwb
 * Date: 2021/9/12 9:12
 * Describe: 实现服务发现（基于Zookeeper）
 */
@Slf4j
@Component
public class ZkServiceDiscovery implements ServiceDiscovery {

    //zk的ip:port
    @Value("${rpc.registry_address}")
    private String zkAddress;

    //服务调用次数  计数 同时用来实现轮询
    private static AtomicInteger atomicInteger = new AtomicInteger(0);

    //创建zk服务发现对象，必须知道zk的地址
//    public ZkServiceDiscovery(String zkAddress){this.zkAddress = zkAddress;}

    /**
     *
     * @param serviceName 服务的名字
     * @return ip:port
     */
    @Override
    public String discover(String serviceName) {
        //创建zk客户端
        ZkClient zkClient = new ZkClient(zkAddress, Contant.ZK_SESSION_TIMEOUT, Contant.ZK_CONNECTION_TIMEOUT);
        log.info("success connect zookeeper");

        try{
            String servicePath = Contant.ZK_REGISTRY_PATH + "/" + serviceName;
            if(!zkClient.exists(servicePath)){
                throw new RuntimeException("can not find service node name:"+servicePath);
            }
            List<String> addressList = zkClient.getChildren(servicePath);
            if(addressList.size()==0){
                throw new RuntimeException("can not find any address node on path:"+servicePath);
            }
            String address = null;

            if(addressList.size()==1){
                //只有一个地址提供服务
                address = addressList.get(0);
                log.info("only one address provider service");
            }else{
                //存在多个地址提供服务
                int next;
                while (true){
                    int cur = atomicInteger.get();
                    next = (cur+1) % addressList.size();
                    if(atomicInteger.compareAndSet(cur,cur+1)){
                        break;
                    }
                }
                 address = addressList.get(next);
                log.info("many address provider service");
            }
            //  /registry/com.xx.xxService + "/" + address-00001
            String addressPath = servicePath + "/" + address;

            String ipPort = (String)zkClient.readData(addressPath);

            return ipPort;

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            zkClient.close();
        }
        return null;
    }
}
